#include "gtkcelllayout.h"
#include "gtkcellarea.h"
+/* GObjectClass */
+static void gtk_cell_area_dispose (GObject *object);
+static void gtk_cell_area_finalize (GObject *object);
+
/* GtkCellAreaClass */
static void gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
GtkWidget *widget,
gint *minimum_width,
gint *natural_width);
-
/* GtkCellLayoutIface */
static void gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface);
static void gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
GtkCellRenderer *renderer,
const gchar *attribute,
gint id);
+static void gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
+ GtkCellRenderer *cell,
+ GtkCellLayoutDataFunc func,
+ gpointer func_data,
+ GDestroyNotify destroy);
static void gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
GtkCellRenderer *renderer);
+static void gtk_cell_area_reorder (GtkCellLayout *cell_layout,
+ GtkCellRenderer *cell,
+ gint position);
static GList *gtk_cell_area_get_cells (GtkCellLayout *cell_layout);
+/* GtkCellLayoutDataFunc handling */
+typedef struct {
+ GtkCellLayoutDataFunc func;
+ gpointer data;
+ GDestroyNotify destroy;
+} CustomCellData;
+
+static CustomCellData *custom_cell_data_new (GtkCellLayoutDataFunc func,
+ gpointer data,
+ GDestroyNotify destroy);
+static void custom_cell_data_free (CustomCellData *custom);
+
+/* Struct to pass data while looping over
+ * cell renderer attributes
+ */
+typedef struct {
+ GtkCellArea *area;
+ GtkTreeModel *model;
+ GtkTreeIter *iter;
+} AttributeData;
+
+struct _GtkCellAreaPrivate
+{
+ GHashTable *custom_cell_data;
+};
+
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
gtk_cell_area_cell_layout_init));
-
static void
gtk_cell_area_init (GtkCellArea *area)
{
+ GtkCellAreaPrivate *priv;
+ area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
+ GTK_TYPE_CELL_AREA,
+ GtkCellAreaPrivate);
+ priv = area->priv;
+
+ priv->custom_cell_data = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ (GDestroyNotify)custom_cell_data_free);
}
static void
gtk_cell_area_class_init (GtkCellAreaClass *class)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ /* GObjectClass */
+ object_class->dispose = gtk_cell_area_dispose;
+ object_class->finalize = gtk_cell_area_finalize;
+
/* general */
- class->add = NULL;
- class->remove = NULL;
- class->forall = NULL;
- class->event = NULL;
- class->render = NULL;
+ class->add = NULL;
+ class->remove = NULL;
+ class->forall = NULL;
+ class->event = NULL;
+ class->render = NULL;
/* attributes */
class->attribute_connect = NULL;
class->attribute_disconnect = NULL;
- class->attribute_apply = NULL;
class->attribute_forall = NULL;
/* geometry */
class->get_preferred_height = NULL;
class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
+
+ g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
+}
+
+
+/*************************************************************
+ * GObjectClass *
+ *************************************************************/
+static void
+gtk_cell_area_finalize (GObject *object)
+{
+ GtkCellArea *area = GTK_CELL_AREA (object);
+ GtkCellAreaPrivate *priv = area->priv;
+
+ /* All cell renderers should already be removed at this point,
+ * just kill our hash table here.
+ */
+ g_hash_table_destroy (priv->custom_cell_data);
+
+ G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
+}
+
+
+static void
+gtk_cell_area_dispose (GObject *object)
+{
+ /* This removes every cell renderer that may be added to the GtkCellArea,
+ * subclasses should be breaking references to the GtkCellRenderers
+ * at this point.
+ */
+ gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
+
+ G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
}
+/*************************************************************
+ * GtkCellAreaClass *
+ *************************************************************/
+static void
+gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
+ GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ /* If the area doesnt do height-for-width, fallback on base preferred height */
+ GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, widget, minimum_height, natural_height);
+}
+
+static void
+gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
+ GtkWidget *widget,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ /* If the area doesnt do width-for-height, fallback on base preferred width */
+ GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, widget, minimum_width, natural_width);
+}
+
/*************************************************************
* GtkCellLayoutIface *
*************************************************************/
+static CustomCellData *
+custom_cell_data_new (GtkCellLayoutDataFunc func,
+ gpointer data,
+ GDestroyNotify destroy)
+{
+ CustomCellData *custom = g_slice_new (CustomCellData);
+
+ custom->func = func;
+ custom->data = data;
+ custom->destroy = destroy;
+
+ return custom;
+}
+
+static void
+custom_cell_data_free (CustomCellData *custom)
+{
+ if (custom->destroy)
+ custom->destroy (custom->data);
+
+ g_slice_free (CustomCellData, custom);
+}
+
static void
gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
{
- iface->pack_start = gtk_cell_area_pack_default;
- iface->pack_end = gtk_cell_area_pack_default;
- iface->clear = gtk_cell_area_clear;
- iface->add_attribute = gtk_cell_area_add_attribute;
- iface->clear_attributes = gtk_cell_area_clear_attributes;
- iface->get_cells = gtk_cell_area_get_cells;
+ iface->pack_start = gtk_cell_area_pack_default;
+ iface->pack_end = gtk_cell_area_pack_default;
+ iface->clear = gtk_cell_area_clear;
+ iface->add_attribute = gtk_cell_area_add_attribute;
+ iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
+ iface->clear_attributes = gtk_cell_area_clear_attributes;
+ iface->reorder = gtk_cell_area_reorder;
+ iface->get_cells = gtk_cell_area_get_cells;
}
static void
g_list_free (cells);
}
-
static void
gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
GtkCellRenderer *renderer,
renderer, attribute, id);
}
-
typedef struct {
const gchar *attribute;
gchar id;
*accum = g_list_prepend (*accum, attrib);
}
+static void
+gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
+ GtkCellRenderer *cell,
+ GtkCellLayoutDataFunc func,
+ gpointer func_data,
+ GDestroyNotify destroy)
+{
+ GtkCellArea *area = GTK_CELL_AREA (cell_layout);
+ GtkCellAreaPrivate *priv = area->priv;
+ CustomCellData *custom;
+
+ if (func)
+ {
+ custom = custom_cell_data_new (func, func_data, destroy);
+ g_hash_table_insert (priv->custom_cell_data, cell, custom);
+ }
+ else
+ g_hash_table_remove (priv->custom_cell_data, cell);
+}
+
+
static void
gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
GtkCellRenderer *renderer)
g_list_free (attributes);
}
+static void
+gtk_cell_area_reorder (GtkCellLayout *cell_layout,
+ GtkCellRenderer *cell,
+ gint position)
+{
+ g_warning ("GtkCellLayout::reorder not implemented for `%s'",
+ g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
+}
static void
accum_cells (GtkCellRenderer *renderer,
}
-/*************************************************************
- * GtkCellAreaClass *
- *************************************************************/
-static void
-gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
- GtkWidget *widget,
- gint width,
- gint *minimum_height,
- gint *natural_height)
-{
- /* If the area doesnt do height-for-width, fallback on base preferred height */
- GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, widget, minimum_height, natural_height);
-}
-
-static void
-gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
- GtkWidget *widget,
- gint height,
- gint *minimum_width,
- gint *natural_width)
-{
- /* If the area doesnt do width-for-height, fallback on base preferred width */
- GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, widget, minimum_width, natural_width);
-}
-
/*************************************************************
* API *
*************************************************************/
class = GTK_CELL_AREA_GET_CLASS (area);
+ /* Remove any custom cell data func we have for this renderer */
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (area),
+ renderer, NULL, NULL, NULL);
+
if (class->remove)
class->remove (area, renderer);
else
g_type_name (G_TYPE_FROM_INSTANCE (area)));
}
-
/* Attributes */
void
gtk_cell_area_attribute_connect (GtkCellArea *area,
g_type_name (G_TYPE_FROM_INSTANCE (area)));
}
-void
-gtk_cell_area_attribute_apply (GtkCellArea *area,
- gint id,
- GValue *value)
-{
- GtkCellAreaClass *class;
-
- g_return_if_fail (GTK_IS_CELL_AREA (area));
- g_return_if_fail (G_IS_VALUE (value));
-
- class = GTK_CELL_AREA_GET_CLASS (area);
-
- if (class->attribute_apply)
- class->attribute_apply (area, id, value);
- else
- g_warning ("GtkCellAreaClass::attribute_apply not implemented for `%s'",
- g_type_name (G_TYPE_FROM_INSTANCE (area)));
-}
-
void
gtk_cell_area_attribute_forall (GtkCellArea *area,
GtkCellRenderer *renderer,
class = GTK_CELL_AREA_GET_CLASS (area);
class->get_preferred_width_for_height (area, widget, height, minimum_width, natural_width);
}
+
+
+static void
+apply_attributes (GtkCellRenderer *renderer,
+ const gchar *attribute,
+ gint id,
+ AttributeData *data)
+{
+ GValue value = { 0, };
+
+ /* For each attribute of each renderer we apply the value
+ * from the model to the renderer here
+ */
+ gtk_tree_model_get_value (data->model, data->iter, id, &value);
+ g_object_set_property (G_OBJECT (renderer), attribute, &value);
+ g_value_unset (&value);
+}
+
+static void
+apply_render_attributes (GtkCellRenderer *renderer,
+ AttributeData *data)
+{
+ gtk_cell_area_attribute_forall (data->area, renderer,
+ (GtkCellAttributeCallback)apply_attributes,
+ data);
+}
+
+static void
+apply_custom_cell_data (GtkCellRenderer *renderer,
+ CustomCellData *custom,
+ AttributeData *data)
+{
+ g_assert (custom->func);
+
+ /* For each renderer that has a GtkCellLayoutDataFunc set,
+ * go ahead and envoke it to apply the data from the model
+ */
+ custom->func (GTK_CELL_LAYOUT (data->area), renderer,
+ data->model, data->iter, custom->data);
+}
+
+void
+gtk_cell_area_apply_attributes (GtkCellArea *area,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ GtkCellAreaPrivate *priv;
+ AttributeData data;
+
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
+ g_return_if_fail (iter != NULL);
+
+ priv = area->priv;
+
+ /* For every cell renderer, for every attribute, apply the attribute */
+ data.area = area;
+ data.model = tree_model;
+ data.iter = iter;
+ gtk_cell_area_forall (area, (GtkCellCallback)apply_render_attributes, &data);
+
+ /* Now go over any custom cell data functions */
+ g_hash_table_foreach (priv->custom_cell_data, (GHFunc)apply_custom_cell_data, &data);
+}